package cs236369.hw5.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.log4j.Logger;
import org.springframework.core.io.DefaultResourceLoader;

public class ResourceLoader
{

    private static DefaultResourceLoader loader = new DefaultResourceLoader();
    private static int MAX_SIZE = 8000;

    /**
     * the stream is probably not resetable, if you want to reset consider using the
     * getResourceAsByteArrrayInputStream. search by this order -> in jar/code path -> in jar -> in
     * user dir -> as absolute path
     * 
     * @param uri
     *            path for the resource to load
     * @return ByteArrayInputStream of the loaded resource
     * @throws IOException
     */
    public static InputStream getResourceAsStream(String uri) throws IOException
    {
        final Logger logger = Logger.getLogger(ResourceLoader.class);
        String p = "";
        if (uri == null)
        {
            throw new IOException("can't open null");
        }
        try
        {
            final String classpath = ResourceLoader.class.getProtectionDomain().getCodeSource()
                    .getLocation().getPath();
            final String path = new File(classpath).getParent();
            final File target = new File(path, uri);
            p = target.getAbsolutePath();
            logger.debug("trying to open: " + p);
            return new FileInputStream(target);
        }
        catch (final IOException e)
        {
            logger.debug("failed to open: " + p);
        }
        try
        // loading the resource from the path of the code/ jar
        {
            p = "/" + uri;
            logger.debug("trying to open: " + p);
            return loader.getResource(p).getInputStream();
        }
        catch (final IOException e)
        {
            // resource is not inside jar.
            logger.debug("failed to open: " + p);
        }
        try
        {
            p = "file:" + System.getProperty("user.dir").replace(File.separator, "/") + "/" + uri;
            logger.debug("trying to open: " + p);
            return loader.getResource(p).getInputStream();
        }
        catch (final IOException e)
        {
            // resource is not in user.dir
            logger.debug("failed to open: " + p);
        }
        try
        // loading the resource from absolute path
        {
            p = "file:/" + uri;
            logger.debug("trying to open: " + p);
            return loader.getResource(p).getInputStream();
        }
        catch (final IOException e)
        {

            logger.debug("failed to open: " + p);
            throw new IOException(uri + " resource was not found");
        }
    }

    /**
     * if a resource is need to be resetable use this
     * 
     * @param stream
     *            to be converted to ByteArrayInputStream
     * @return ByteArrayInputStream of the loaded resource
     * @throws IOException
     */
    public static ByteArrayInputStream getAsByteArrayInputStream(InputStream stream)
            throws IOException
    {
        if (stream == null)
        {
            throw new IOException("can't open null");
        }
        final byte[] buff = new byte[MAX_SIZE];
        int read = 0;
        final ByteArrayOutputStream bao = new ByteArrayOutputStream();
        while ((read = stream.read(buff)) != -1)
        {
            bao.write(buff, 0, read);
        }
        final byte[] data = bao.toByteArray();
        final ByteArrayInputStream bin = new ByteArrayInputStream(data);
        return bin;
    }

    /**
     * if a resource is need to be resetable use this
     * 
     * @param uri
     *            path for the resource to load
     * @return ByteArrayInputStream of the loaded resource
     * @throws IOException
     */
    public static ByteArrayInputStream getResourceAsByteArrayInputStream(String uri)
            throws IOException
    {
        final InputStream is = getResourceAsStream(uri);
        return getAsByteArrayInputStream(is);
    }
}
